package com.dolphin.aiagentplatform.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dolphin.aiagentplatform.constant.UserRoleConst;
import com.dolphin.aiagentplatform.exception.BusinessException;
import com.dolphin.aiagentplatform.mapper.UserMapper;
import com.dolphin.aiagentplatform.model.dto.user.*;
import com.dolphin.aiagentplatform.model.entity.User;
import com.dolphin.aiagentplatform.model.vo.user.UserPageVO;
import com.dolphin.aiagentplatform.model.vo.user.UserVO;
import com.dolphin.aiagentplatform.service.UserService;
import com.dolphin.aiagentplatform.utils.RoleCheckUtils;
import com.dolphin.aiagentplatform.utils.SecurityUtils;
import com.dolphin.aiagentplatform.utils.TokenManager;
import com.dolphin.aiagentplatform.utils.ValidationUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

import static com.dolphin.aiagentplatform.constant.ResponseCodeConst.*;

@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService {

    @Resource
    private UserMapper userMapper;
    
    @Resource
    private TokenManager tokenManager;

    @Override
    public Long register(UserRegisterDTO userRegisterDTO) {
        // 1.参数校验
        if (userRegisterDTO == null) {
            throw new BusinessException(PARAMS_ERROR, "必填项不能为空");
        }
        String account = userRegisterDTO.getAccount();
        String password = userRegisterDTO.getPassword();
        String confirmPassword = userRegisterDTO.getConfirmPassword();

        if (!ValidationUtils.isValidAccount(account)) {
            throw new BusinessException(PARAMS_ERROR, "账号必须为3~16位，且只能包含字母、数字和下划线");
        }
        if (!ValidationUtils.isValidPassword(password)) {
            throw new BusinessException(PARAMS_ERROR, "密码必须为8~20位，且只能包含字母和数字");
        }
        if (!password.equals(confirmPassword)) {
            throw new BusinessException(PARAMS_ERROR, "两次密码不一致");
        }

        // 验证可选字段
        String phone = userRegisterDTO.getPhone();
        String email = userRegisterDTO.getEmail();

        // 如果提供了手机号，进行格式验证
        if (phone != null && !phone.isEmpty()) {
            if (!ValidationUtils.isValidPhone(phone)) {
                throw new BusinessException(PARAMS_ERROR, "手机号格式不正确");
            }
        }

        // 如果提供了邮箱，进行格式验证
        if (email != null && !email.isEmpty()) {
            if (!ValidationUtils.isValidEmail(email)) {
                throw new BusinessException(PARAMS_ERROR, "邮箱格式不正确");
            }
        }

        synchronized (account.intern()) {
            // 2.查询同名账号是否已存在（无论是否已注销）
            QueryWrapper<User> accountWrapper = new QueryWrapper<User>().eq("account", account);
            User existUser = getOne(accountWrapper);

            if (existUser != null) {
                // 账号存在但已注销的情况
                if (existUser.getIsDelete() != null && existUser.getIsDelete() == 1) {
                    throw new BusinessException(FORBIDDEN_ERROR, "该账号已被注销，无法重新注册");
                }
                // 账号存在且未注销的情况
                throw new BusinessException(FORBIDDEN_ERROR, "账号已存在");
            }

            // 3.检查邮箱是否已被注册（如果提供）
            if (email != null && !email.isEmpty()) {
                QueryWrapper<User> emailWrapper = new QueryWrapper<User>().eq("email", email);
                if (userMapper.selectCount(emailWrapper) > 0) {
                    throw new BusinessException(FORBIDDEN_ERROR, "邮箱已被注册");
                }
            }

            // 检查手机号是否已被注册（如果提供）
            if (phone != null && !phone.isEmpty()) {
                QueryWrapper<User> phoneWrapper = new QueryWrapper<User>().eq("phone", phone);
                if (userMapper.selectCount(phoneWrapper) > 0) {
                    throw new BusinessException(FORBIDDEN_ERROR, "手机号已被注册");
                }
            }

            // 4.使用SecurityUtils加密密码
            String encryptPassword = SecurityUtils.encryptPassword(password);

            // 5.新增user
            User user = new User();
            user.setAccount(account);
            user.setPassword(encryptPassword);

            // 获取用户名或生成随机用户名
            String username = userRegisterDTO.getUsername();
            if (username == null || username.isEmpty()) {
                // 使用SecurityUtils生成随机用户名
                username = SecurityUtils.generateRandomUsername(10);
            }
            user.setUsername(username);

            // 设置手机号和邮箱（如果提供）
            if (phone != null && !phone.isEmpty()) {
                user.setPhone(phone);
            }
            if (email != null && !email.isEmpty()) {
                user.setEmail(email);
            }

            // 设置默认角色为普通用户
            user.setRole(UserRoleConst.NORMAL.getCode());

            // 设置状态为启用
            user.setEnabled(1);

            // 保存用户
            boolean saveSuccess = save(user);
            if (!saveSuccess) {
                throw new BusinessException(SYSTEM_ERROR, "注册失败");
            }
            return user.getId();
        }
    }

    @Override
    public UserVO login(UserLoginDTO userLoginDTO, HttpServletRequest request, HttpServletResponse response) {
        // 1.参数非空校验
        if (userLoginDTO == null) {
            throw new BusinessException(PARAMS_ERROR, "登录参数不能为空");
        }
        String account = userLoginDTO.getAccount();
        String password = userLoginDTO.getPassword();

        if (!ValidationUtils.isValidAccount(account)) {
            throw new BusinessException(PARAMS_ERROR, "账号格式不正确");
        }
        if (password == null || password.isEmpty()) {
            throw new BusinessException(PARAMS_ERROR, "密码不能为空");
        }

        // 2.查询用户是否存在
        QueryWrapper<User> queryWrapper = new QueryWrapper<User>()
                .eq("account", account);
        User user = getOne(queryWrapper);

        // 3.用户不存在，直接返回账号或密码错误
        if (user == null) {
            throw new BusinessException(PARAMS_ERROR, "账号或密码错误");
        }

        // 4.检查用户是否已注销
        if (user.getIsDelete() != null && user.getIsDelete() == 1) {
            throw new BusinessException(FORBIDDEN_ERROR, "该账号已注销，无法登录");
        }

        // 5.检查用户状态是否禁用
        if (user.getEnabled() != null && user.getEnabled() == 0) {
            throw new BusinessException(FORBIDDEN_ERROR, "账号已被禁用，请联系管理员");
        }

        // 6.校验密码
        String encryptPassword = SecurityUtils.encryptPassword(password);
        log.debug("用户密码：{}", encryptPassword);
        if (!encryptPassword.equals(user.getPassword())) {
            throw new BusinessException(PARAMS_ERROR, "账号或密码错误");
        }

        // 7.登录成功，创建用户令牌并保存到Redis
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(user, userVO);
        
        // 生成Token并保存到Redis
        String token = tokenManager.createUserToken(response, userVO);
        userVO.setToken(token); // 将token设置到返回对象中，方便前端存储

        return userVO;
    }

    @Override
    public UserVO getLoginUserInfo(HttpServletRequest request) {
        // 从TokenManager获取当前登录用户
        UserVO userVO = tokenManager.getLoginUser(request);
        if (userVO == null) {
            throw new BusinessException(NOT_LOGIN_ERROR, "用户未登录");
        }

        // 从TokenManager中获取用户ID，保证数据的实时性，重新查询数据库
        Long userId = userVO.getId();

        // 使用MyBatisPlus的LambdaQuery风格查询最新用户信息
        User latestUser = lambdaQuery()
                .eq(User::getId, userId)
                .eq(User::getEnabled, 1) // 确保用户仍然处于启用状态
                .one();

        // 如果用户不存在或已被禁用
        if (latestUser == null) {
            // 移除用户令牌
            tokenManager.removeUserToken(request, null);
            throw new BusinessException(NOT_LOGIN_ERROR, "用户不存在或已被禁用");
        }

        // 脱敏用户信息
        UserVO updatedUserVO = new UserVO();
        BeanUtils.copyProperties(latestUser, updatedUserVO);
        
        // 保留原始token
        updatedUserVO.setToken(userVO.getToken());

        return updatedUserVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updatePassword(UserUpdatePasswordDTO userUpdatePasswordDTO, HttpServletRequest request, HttpServletResponse response) {
        // 1.参数校验
        if (userUpdatePasswordDTO == null) {
            throw new BusinessException(PARAMS_ERROR, "参数不能为空");
        }
        String oldPassword = userUpdatePasswordDTO.getOldPassword();
        String newPassword = userUpdatePasswordDTO.getNewPassword();
        String confirmPassword = userUpdatePasswordDTO.getConfirmPassword();

        if (oldPassword == null || oldPassword.isEmpty()) {
            throw new BusinessException(PARAMS_ERROR, "原密码不能为空");
        }

        // 校验新密码格式
        if (!ValidationUtils.isValidPassword(newPassword)) {
            throw new BusinessException(PARAMS_ERROR, "新密码必须为8~20位，且只能包含字母和数字");
        }

        // 确认密码验证
        if (!newPassword.equals(confirmPassword)) {
            throw new BusinessException(PARAMS_ERROR, "两次密码输入不一致");
        }

        // 2.获取当前登录用户
        UserVO userVO = tokenManager.getLoginUser(request);
        if (userVO == null) {
            throw new BusinessException(NOT_LOGIN_ERROR, "用户未登录");
        }

        // 3.查询用户信息
        Long userId = userVO.getId();
        User user = getById(userId);
        if (user == null) {
            throw new BusinessException(NOT_LOGIN_ERROR, "用户不存在");
        }

        // 4.验证原密码
        String encryptedOldPassword = SecurityUtils.encryptPassword(oldPassword);
        if (!encryptedOldPassword.equals(user.getPassword())) {
            throw new BusinessException(PARAMS_ERROR, "原密码错误");
        }

        // 5.加密新密码
        String encryptedNewPassword = SecurityUtils.encryptPassword(newPassword);

        // 6.更新密码
        User updateUser = new User();
        updateUser.setId(userId);
        updateUser.setPassword(encryptedNewPassword);
        boolean result = updateById(updateUser);

        if (!result) {
            throw new BusinessException(SYSTEM_ERROR, "密码修改失败，请稍后重试");
        }

        // 7.更新成功后，清除用户登录状态，要求重新登录
        tokenManager.removeUserToken(request, response);

        log.debug("用户密码修改成功，userId:{}", userId);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserVO updateUserProfile(UserUpdateProfileDTO userUpdateProfileDTO, HttpServletRequest request) {
        // 1.参数校验
        if (userUpdateProfileDTO == null) {
            throw new BusinessException(PARAMS_ERROR, "参数不能为空");
        }

        // 2.获取当前登录用户
        UserVO userVO = tokenManager.getAndCheckLoginUser(request);
        Long userId = userVO.getId();

        // 3.查询用户信息
        User user = getById(userId);
        if (user == null) {
            throw new BusinessException(NOT_LOGIN_ERROR, "用户不存在");
        }

        // 4.处理各字段的更新
        User updateUser = new User();
        updateUser.setId(userId);

        // 处理用户名
        String username = userUpdateProfileDTO.getUsername();
        if (username != null && !username.isEmpty()) {
            // 校验用户名格式
            if (!ValidationUtils.isValidUsername(username)) {
                throw new BusinessException(PARAMS_ERROR, "用户名必须为2~20位，且只能包含中文、字母、数字和下划线");
            }
            updateUser.setUsername(username);
        }

        // 处理手机号
        String phone = userUpdateProfileDTO.getPhone();
        if (phone != null) {
            if (phone.isEmpty()) {
                // 用户想要清空手机号
                updateUser.setPhone("");
            } else {
                // 校验手机号格式
                if (!ValidationUtils.isValidPhone(phone)) {
                    throw new BusinessException(PARAMS_ERROR, "手机号格式不正确");
                }

                // 检查手机号是否已被其他用户使用
                if (!phone.equals(user.getPhone())) {
                    QueryWrapper<User> phoneWrapper = new QueryWrapper<User>()
                            .eq("phone", phone)
                            .ne("id", userId);
                    if (userMapper.selectCount(phoneWrapper) > 0) {
                        throw new BusinessException(PARAMS_ERROR, "手机号已被其他用户使用");
                    }
                }
                updateUser.setPhone(phone);
            }
        }

        // 处理邮箱
        String email = userUpdateProfileDTO.getEmail();
        if (email != null) {
            if (email.isEmpty()) {
                // 用户想要清空邮箱
                updateUser.setEmail("");
            } else {
                // 校验邮箱格式
                if (!ValidationUtils.isValidEmail(email)) {
                    throw new BusinessException(PARAMS_ERROR, "邮箱格式不正确");
                }

                // 检查邮箱是否已被其他用户使用
                if (!email.equals(user.getEmail())) {
                    QueryWrapper<User> emailWrapper = new QueryWrapper<User>()
                            .eq("email", email)
                            .ne("id", userId);
                    if (userMapper.selectCount(emailWrapper) > 0) {
                        throw new BusinessException(PARAMS_ERROR, "邮箱已被其他用户使用");
                    }
                }
                updateUser.setEmail(email);
            }
        }

        // 处理头像URL
        String avatar = userUpdateProfileDTO.getAvatar();
        if (avatar != null) {
            if (!avatar.isEmpty()) {
                // 这里可以添加对URL格式的校验
                if (!ValidationUtils.isValidUrl(avatar)) {
                    throw new BusinessException(PARAMS_ERROR, "头像URL格式不正确");
                }
            }
            updateUser.setAvatar(avatar);
        }

        // 5.更新用户信息
        boolean result = updateById(updateUser);
        if (!result) {
            throw new BusinessException(SYSTEM_ERROR, "更新个人资料失败，请稍后重试");
        }

        // 6.获取更新后的用户信息并返回
        User updatedUser = getById(userId);
        UserVO updatedUserVO = new UserVO();
        BeanUtils.copyProperties(updatedUser, updatedUserVO);
        
        // 保留令牌信息
        updatedUserVO.setToken(userVO.getToken());

        log.debug("用户资料修改成功，userId:{}", userId);
        return updatedUserVO;
    }

    @Override
    public UserPageVO listUserByPage(UserPageQueryDTO userPageQueryDTO, HttpServletRequest request) {
        // 1.参数校验
        if (userPageQueryDTO == null) {
            throw new BusinessException(PARAMS_ERROR, "查询参数不能为空");
        }

        // 2.校验当前用户是否有权限查询（仅管理员可查询用户列表）
        UserVO userVO = tokenManager.getAndCheckLoginUser(request);
        RoleCheckUtils.checkAdmin(userVO);

        // 3.构建查询条件
        Integer current = userPageQueryDTO.getCurrent();
        Integer pageSize = userPageQueryDTO.getPageSize();

        // 参数校验和默认值设置
        if (current == null || current < 1) {
            current = 1;
        }
        if (pageSize == null || pageSize < 1 || pageSize > 100) {
            pageSize = 10;
        }

        // 构建查询条件
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getIsDelete, 0); // 只查询未删除的用户

        // 添加模糊查询条件（如果提供了对应参数）
        String username = userPageQueryDTO.getUsername();
        if (username != null && !username.isEmpty()) {
            queryWrapper.like(User::getUsername, username);
        }

        String account = userPageQueryDTO.getAccount();
        if (account != null && !account.isEmpty()) {
            queryWrapper.like(User::getAccount, account);
        }

        String phone = userPageQueryDTO.getPhone();
        if (phone != null && !phone.isEmpty()) {
            queryWrapper.like(User::getPhone, phone);
        }

        String email = userPageQueryDTO.getEmail();
        if (email != null && !email.isEmpty()) {
            queryWrapper.like(User::getEmail, email);
        }

        // 按创建时间降序排序
        queryWrapper.orderByDesc(User::getCreateTime);

        // 4.执行分页查询
        Page<User> page = new Page<>(current, pageSize);
        this.page(page, queryWrapper);

        // 5.封装返回结果
        UserPageVO userPageVO = new UserPageVO();
        userPageVO.setTotal(page.getTotal());
        userPageVO.setPages(page.getPages());
        userPageVO.setCurrent(page.getCurrent());
        userPageVO.setSize(page.getSize());

        // 6.对用户数据进行脱敏处理
        List<UserVO> userVOList = page.getRecords().stream().map(user -> {
            UserVO vo = new UserVO();
            BeanUtils.copyProperties(user, vo);
            return vo;
        }).collect(Collectors.toList());

        userPageVO.setRecords(userVOList);

        log.debug("分页查询用户列表，当前页：{}，每页记录数：{}，总记录数：{}",
                current, pageSize, userPageVO.getTotal());

        return userPageVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateUserRole(UserUpdateRoleDTO userUpdateRoleDTO, HttpServletRequest request) {
        // 1.参数校验
        if (userUpdateRoleDTO == null) {
            throw new BusinessException(PARAMS_ERROR, "参数不能为空");
        }

        Long userId = userUpdateRoleDTO.getUserId();
        Integer role = userUpdateRoleDTO.getRole();

        if (userId == null || userId <= 0) {
            throw new BusinessException(PARAMS_ERROR, "用户ID不合法");
        }

        // 检查角色值是否合法
        if (role == null ||
                (role != UserRoleConst.ADMIN.getCode() &&
                        role != UserRoleConst.NORMAL.getCode() &&
                        role != UserRoleConst.VIP.getCode())) {
            throw new BusinessException(NO_AUTH_ERROR, "无权限");
        }

        // 2.校验当前用户是否有权限修改（仅管理员可操作）
        UserVO adminUser = tokenManager.getAndCheckLoginUser(request);
        RoleCheckUtils.checkAdmin(adminUser);

        // 3.检查目标用户是否存在
        User user = getById(userId);
        if (user == null) {
            throw new BusinessException(NOT_FOUND_ERROR, "目标用户不存在");
        }

        // 4.防止管理员修改自己的角色
        if (userId.equals(adminUser.getId())) {
            throw new BusinessException(FORBIDDEN_ERROR, "管理员不能修改自己的角色");
        }

        // 5.更新用户角色
        User updateUser = new User();
        updateUser.setId(userId);
        updateUser.setRole(role);
        boolean result = updateById(updateUser);

        if (!result) {
            throw new BusinessException(SYSTEM_ERROR, "修改用户角色失败，请稍后重试");
        }

        // 6.记录操作日志
        log.info("管理员{}修改用户{}的角色为{}，备注：{}",
                adminUser.getUsername(), userId, role, userUpdateRoleDTO.getRemark());

        return true;
    }

    @Override
    public UserVO getUserById(Long userId, HttpServletRequest request) {
        // 1.参数校验
        if (userId == null || userId <= 0) {
            throw new BusinessException(PARAMS_ERROR, "用户ID不合法");
        }

        // 2.校验当前用户是否有权限查询（仅管理员可查询其他用户信息）
        UserVO currentUser = tokenManager.getAndCheckLoginUser(request);
        RoleCheckUtils.checkAdmin(currentUser);

        // 3.查询用户信息
        User user = getById(userId);
        if (user == null || user.getIsDelete() == 1) {
            throw new BusinessException(NOT_FOUND_ERROR, "用户不存在");
        }

        // 4.脱敏处理并返回
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(user, userVO);

        log.debug("管理员{}查询用户{}的信息", currentUser.getUsername(), userId);
        return userVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateUserStatus(UserUpdateStatusDTO userUpdateStatusDTO, HttpServletRequest request) {
        // 1.参数校验
        if (userUpdateStatusDTO == null) {
            throw new BusinessException(PARAMS_ERROR, "参数不能为空");
        }

        Long userId = userUpdateStatusDTO.getUserId();
        Integer enabled = userUpdateStatusDTO.getEnabled();

        if (userId == null || userId <= 0) {
            throw new BusinessException(PARAMS_ERROR, "用户ID不合法");
        }

        if (enabled == null || (enabled != 0 && enabled != 1)) {
            throw new BusinessException(PARAMS_ERROR, "状态参数不合法");
        }

        // 2.校验当前用户是否有权限修改（仅管理员可操作）
        UserVO adminUser = tokenManager.getAndCheckLoginUser(request);
        RoleCheckUtils.checkAdmin(adminUser);

        // 3.检查目标用户是否存在
        User user = getById(userId);
        if (user == null || user.getIsDelete() == 1) {
            throw new BusinessException(NOT_FOUND_ERROR, "目标用户不存在");
        }

        // 4.防止管理员禁用自己的账号
        if (userId.equals(adminUser.getId())) {
            throw new BusinessException(FORBIDDEN_ERROR, "不能修改自己的账号状态");
        }

        // 5.更新用户状态
        User updateUser = new User();
        updateUser.setId(userId);
        updateUser.setEnabled(enabled);
        boolean result = updateById(updateUser);

        if (!result) {
            throw new BusinessException(SYSTEM_ERROR, "修改用户状态失败，请稍后重试");
        }

        // 6. 如果是禁用操作，清除该用户的所有令牌
        // 这里需要Redis操作，暂不实现完整功能
        if (enabled == 0) {
            log.info("用户{}被禁用，该用户的所有会话应当被清除", userId);
        }

        // 7.记录操作日志
        String statusDesc = enabled == 1 ? "启用" : "禁用";
        log.info("管理员{}{}用户{}，备注：{}",
                adminUser.getUsername(), statusDesc, userId, userUpdateStatusDTO.getRemark());

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deactivateAccount(HttpServletRequest request, HttpServletResponse response) {
        // 1.获取当前登录用户
        UserVO userVO = tokenManager.getAndCheckLoginUser(request);
        Long userId = userVO.getId();

        // 2.检查是否为管理员账号，禁止管理员自我注销
        if (userVO.getRole() != null && userVO.getRole() == UserRoleConst.ADMIN.getCode()) {
            throw new BusinessException(FORBIDDEN_ERROR, "管理员账号不能注销");
        }

        // 3.查询用户是否存在
        User user = getById(userId);
        if (user == null) {
            throw new BusinessException(NOT_FOUND_ERROR, "用户不存在");
        }

        // 4.执行逻辑删除
        User updateUser = new User();
        updateUser.setId(userId);
        updateUser.setIsDelete(1);  // 设置逻辑删除标记

        // 额外处理：禁用账号
        updateUser.setEnabled(0);

        // 处理账号安全，防止同名账号被再次注册

        // 执行更新
        boolean result = updateById(updateUser);
        if (!result) {
            throw new BusinessException(SYSTEM_ERROR, "注销账号失败，请稍后重试");
        }

        // 5.清除用户令牌
        tokenManager.removeUserToken(request, response);

        // 6.记录操作日志
        log.info("用户{}(账号:{})注销成功", userId, user.getAccount());

        return true;
    }
}




